1 Preparations for analysis

Loading packages to simulate and manipulate data.

library(MASS)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages -------------------------------------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.1.1     v dplyr   1.0.6
v tidyr   1.1.3     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
-- Conflicts ----------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
x dplyr::select() masks MASS::select()

2 Simulate data

Data generation was performed according to the following conditions:

  • Correlations: 0.12, 0.20, 0.31, 0.50
  • Sample sizes: 50, 100, 250, 500, 1000
  • Number of replications: 1000

In this way, 20 dataframes are generated with different amounts of data within each of them, which will have 1,000 replications. In total, 20,000 dataframes with observations for analysis.

2.1 Generate matrices and observations

Create the variables that indicate the conditions

set.seed(2020) 
r <- c(0.12, 0.20, 0.31, 0.50) ## Correlations 
n <- c(50, 100, 250, 500, 1000) ## Sample sizes
replic <- 1000
sigma <- list()
for (i in seq_along(r)) { 
  sigma[[i]] <- matrix(data = c(1, rep(r[i], 2), 1),
                       nrow = 2,
                       ncol = 2)
}


# Generar los datos de correlación
df_cor <- list()
for (i in seq_along(sigma)) {
  df_cor[[i]] <- list()
  for (j in seq_along(n)) {
    df_cor[[i]][[j]] <- list()
    for (k in 1:replic) {
      df_cor[[i]][[j]][[k]] <- mvrnorm(n     = n[j],
                                       mu    = rep(0, 2),
                                       Sigma = sigma[[i]]) %>% 
        as_tibble()
    }
  }
}
The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.

2.2 Format the data as dataframe / tibbles

We will assemble the list object in such a way that we can identify by columns the correlation, sample size and replicate number of each observation.

# Unir los datos y pasarlo a formato tidy
temp <- df_cor
df_cor <- list()
for (i in seq_along(sigma)) {
  df_cor[[i]] <- list()
  for (j in seq_along(n)) {
    df_cor[[i]][[j]] <- temp[[i]][[j]] %>% 
      bind_rows(.id = "replic") %>% 
      mutate(replic = as.numeric(replic))
  }
  df_cor[[i]] <- df_cor[[i]] %>% 
    bind_rows(.id = "n") %>% 
    mutate(n = recode(n, "1" = 50, "2" = 100,
                      "3" = 250, "4" = 500, 
                      "5" = 1000))
}

df_cor <- df_cor %>% 
  bind_rows(.id = "correlacion") %>% 
  mutate(correlacion = recode(correlacion, "1" = 0.12,
                              "2" = 0.20, "3" = 0.31,
                              "4" = 0.50)) %>% 
  arrange(correlacion, n, replic)

# Crear data nest
df_nest <- df_cor %>% 
  nest(data = c(V1, V2))

rm(temp, i, j, k)

2.3 Add outliers

Five percent of the data in each data frame will be randomly replaced by outlier correlations different from the one generated. For example, in the case of a dataframe with a correlation of 0.12 and a sample size of 50, 3 pairs of correlations will be randomly replaced with 3 pairs of correlations generated with correlations of 0.20, 0.31 and 0.50.

# Add the number of outliers to be added and their locations Outliers at 5%.
df_work <- df_nest %>% 
  rowwise() %>% 
  mutate(
    ratio_outlier = map_dbl(n,
                        ~ ceiling(0.05*n)),
    posici_rep_m3 = map2(n, ratio_outlier,
                         ~ sample(1:.x, .y)),
    posici_rep_m6 = map2(n, ratio_outlier,
                         ~ sample(1:.x, .y)),
    posici_rep_m3v1 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m3v2 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m3v3 = map2(n, ratio_outlier,
                          ~ sample(1:.x, .y)),
    posici_rep_m6v1 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y)),
    posici_rep_m6v2 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y)),
    posici_rep_m6v3 = map2(n, ratio_outlier,
                           ~ sample(1:.x, .y))
  )

# Add correlations that were not considered
df_work <- df_work %>% 
  mutate(
    correla_a = r[which(correlacion != r)[1]],
    correla_b = r[which(correlacion != r)[2]],
    correla_c = r[which(correlacion != r)[3]]
  )

On the correlations identified to be generated, the data matrix necessary for the multivariate simulation is created as an outlier.

df_work <- df_work %>% 
  mutate(
    matrix = map(correlacion,
                 ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                          nrow = 2,
                          ncol = 2)),
    matrix_a = map(correla_a,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2)),
    matrix_b = map(correla_b,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2)),
    matrix_c = map(correla_c,
                   ~ matrix(data = rep(c(1, rep(.x, 2)), 2), 
                            nrow = 2,
                            ncol = 2))
  ) %>% 
  ungroup()

Aggregate outliers are of 2 types: they vary only by the mean and they vary by the mean and its matrix:

  • outlier_m3: Varies by an mean of 3
  • outlier_m6: Varies by an mean of 6
  • outlier_m3v1: Varies by an mean of 3 and matrix a
  • outlier_m3v2: Varies by an mean of 3 and matrix b
  • outlier_m3v3: Varies by an mean of 3 and matrix c
  • outlier_m6v1: Varies by an mean of 6 and matrix a
  • outlier_m6v2: Varies by an mean of 6 and matrix b
  • outlier_m6v3: Varies by an mean of 6 and matrix c
set.seed(2019) 

df_work <- df_work %>% 
  mutate(
    outlier_m3 = map2(ratio_outlier, matrix, 
                      ~ mvrnorm(n     = .x,
                                mu    = rep(3, 2),
                                Sigma = .y) %>% 
                        as_tibble()),
    outlier_m6 = map2(ratio_outlier, matrix,
                      ~ mvrnorm(n     = .x,
                                mu    = rep(6, 2),
                                Sigma = .y) %>% 
                        as_tibble()),
    outlier_m3v1 = map2(ratio_outlier, matrix_a, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m3v2 = map2(ratio_outlier, matrix_b, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m3v3 = map2(ratio_outlier, matrix_c, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(3, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v1 = map2(ratio_outlier, matrix_a, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v2 = map2(ratio_outlier, matrix_b, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble()),
    outlier_m6v3 = map2(ratio_outlier, matrix_c, 
                        ~ mvrnorm(n     = .x,
                                  mu    = rep(6, 2),
                                  Sigma = .y) %>% 
                          as_tibble())
  )

These new simulated outlier correlations will be inserted into the initially calculated random positions in each dataframe.

df_work <- df_work %>% 
  mutate(
    data_out_m3 = pmap(list(data, posici_rep_m3, outlier_m3),
                       ~ ..1 %>% 
                         slice(- ..2) %>% 
                         bind_rows(..3)),
    data_out_m6 = pmap(list(data, posici_rep_m6, outlier_m6),
                       ~ ..1 %>% 
                         slice(- ..2) %>% 
                         bind_rows(..3)),
    data_out_m3v1 = pmap(list(data, posici_rep_m3v1, outlier_m3v1),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m3v2 = pmap(list(data, posici_rep_m3v2, outlier_m3v2),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m3v3 = pmap(list(data, posici_rep_m3v3, outlier_m3v3),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v1 = pmap(list(data, posici_rep_m6v1, outlier_m6v1),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v2 = pmap(list(data, posici_rep_m6v2, outlier_m6v2),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3)),
    data_out_m6v3 = pmap(list(data, posici_rep_m6v3, outlier_m6v3),
                         ~ ..1 %>% 
                           slice(- ..2) %>% 
                           bind_rows(..3))
  )

Additionally, new dataframes with the same correlation conditions, sample size and number of replications with non-normal data distributions are generated using the algorithm of Vale and Maurelli (1983).

Non-normality conditions were generated on the basis of the work of Sheng & Sheng (2012):

  • skewness = 0.00, kurtosis = − 1.385 (symmetric platykurtic distribution);
  • skewness = 0.00, kurtosis = 25 (symmetric leptokurtic distribution);
  • skewness = 0.96, kurtosis = 0.13 (non-symmetric distribution);
  • skewness = 0.48, kurtosis = − 0.92 (non-symmetric platykurtic distribution);
  • skewness = 2.50, kurtosis = 25 (non-symmetric leptokurtic distribution).
set.seed(2021) 
library(semTools)
Loading required package: lavaan
This is lavaan 0.6-8
lavaan is FREE software! Please report any bugs.
 
###############################################################################
This is semTools 0.5-4
All users of R (or SEM) are invited to submit functions or ideas for functions.
###############################################################################

Attaching package: 㤼㸱semTools㤼㸲

The following object is masked from 㤼㸱package:readr㤼㸲:

    clipboard
df_work <- df_work %>% 
  mutate(
    data_nonorm1 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = c(0),
                                     kurtosis = c(-1.385)) %>% # symmetric platykurtic distribution
                          as_tibble()),
    data_nonorm2 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0,
                                     kurtosis = 25) %>% # symmetric leptokurtic distribution 
                          as_tibble()),
    data_nonorm3 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0.96,
                                     kurtosis = 0.13) %>% # non-symmetric distribution
                          as_tibble()),
    data_nonorm4 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 0.48,
                                     kurtosis = -0.92) %>% # non-symmetric platykurtic distribution
                          as_tibble()),
    data_nonorm5 = map2(n, matrix,
                        ~ mvrnonnorm(n = .x,
                                     mu = rep(0, 2),
                                     Sigma = .y,
                                     skewness = 2.5,
                                     kurtosis = 25) %>% # non-symmetric leptokurtic distribution
                          as_tibble())
  )

Finally, the variables that will no longer be used are eliminated.

df_work <- df_work %>% 
  select(-c(ratio_outlier:outlier_m6v3))

3 Calculation of correlations

3.1 Format tidy data

df_work_tidy <- df_work %>% 
  pivot_longer(
    cols = data:data_nonorm5,
    names_to = "Tipo_Sim",
    values_to = "Data"
  )

3.2 Correlations

library(WRS2)
df_work_tidy <- df_work_tidy %>% 
  mutate(
    cort_pears = map(Data,
                     ~ cor.test(.x$V1, .x$V2,
                                method = "pearson")),
    cort_spear = map(Data,
                     ~ cor.test(.x$V1, .x$V2,
                                method = "spearman")),
    cort_winso = map(Data,
                     ~ wincor(.x$V1, .x$V2,
                              tr = 0.2))
  )

3.3 Obtain the coefficients

df_work_tidy <- df_work_tidy %>% 
  mutate(
    coef_pears = map_dbl(cort_pears,
                         ~ .x$estimate[1]),
    coef_spear = map_dbl(cort_spear,
                         ~ .x$estimate[1]),
    coef_winso = map_dbl(cort_winso,
                         ~ .x$cor[1])
  )

df_work_tidy_simp <- df_work_tidy %>% 
  select(-c(Data:cort_winso))

4 Evaluate simulation

4.1 Calculate RMSEA and Bias

df_work_tidy_simp <- df_work_tidy_simp %>% 
  rowwise() %>% 
  mutate(
    dif_pears = (coef_pears - correlacion)/correlacion,
    dif_spear = (coef_spear - correlacion)/correlacion,
    dif_winso = (coef_winso - correlacion)/correlacion
  ) %>% 
  ungroup()

df_work_tidy_simp <- df_work_tidy_simp %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    rmsea_pears = sqrt(sum(dif_pears^2)/1000),
    sesgo_pears = (sum(dif_pears)/1000),
    rmsea_spear = sqrt(sum(dif_spear^2)/1000),
    sesgo_spear = (sum(dif_spear)/1000),
    rmsea_winso = sqrt(sum(dif_winso^2)/1000),
    sesgo_winso = (sum(dif_winso)/1000)
  ) %>% 
  ungroup()
`summarise()` has grouped output by 'correlacion', 'n'. You can override using the `.groups` argument.
df_work_tidy_simp

4.2 Recode simulation types

df_work_tidy_simp <- df_work_tidy_simp %>% 
  mutate(
    Tipo_Sim = fct_recode(Tipo_Sim,
                          "MVN" = "data",
                          "OL M3" = "data_out_m3",
                          "OL M6" = "data_out_m6",
                          "OL M3 V1" = "data_out_m3v1",
                          "OL M3 V2" = "data_out_m3v2",
                          "OL M3 V3" = "data_out_m3v3",
                          "OL M6 V1" = "data_out_m6v1",
                          "OL M6 V2" = "data_out_m6v2",
                          "OL M6 V3" = "data_out_m6v3",
                          "No-MVN A" = "data_nonorm1",
                          "No-MVN B" = "data_nonorm2",
                          "No-MVN C" = "data_nonorm3",
                          "No-MVN D" = "data_nonorm4",
                          "No-MVN E" = "data_nonorm5"),
    Tipo_Sim = fct_relevel(Tipo_Sim,
                           "MVN", "OL M3", "OL M6", "OL M3 V1", 
                           "OL M3 V2", "OL M3 V3", "OL M6 V1",
                           "OL M6 V2", "OL M6 V3")
  ) %>% 
  arrange(correlacion, n, Tipo_Sim)

4.3 Complete table about RMSEA and Bias

df_work_tidy_simp_A <- df_work_tidy_simp %>% 
  relocate(contains("sesgo"), .after = "rmsea_winso")

df_work_tidy_simp_A

4.4 Recalculation of RMSEA and Bias grouping conditions

df_work_tidy_simp_B <- df_work_tidy_simp %>%
  mutate(
    Tipo_Sim = fct_collapse(Tipo_Sim,
                            "MVN" = "MVN",
                            "MVN OL M3" = "OL M3",
                            "MVN OL M6" = "OL M6",
                            "MVN OL M3V" = c("OL M3 V1", "OL M3 V2", "OL M3 V3"),
                            "MVN OL M6V" = c("OL M6 V1", "OL M6 V2", "OL M6 V3"),
                            "No-MVN" = c("No-MVN A", "No-MVN C", "No-MVN D"),
                            "No-MVN ks+" = c("No-MVN B", "No-MVN E")
    )
  ) %>% 
  relocate(contains("sesgo"), .after = "rmsea_winso")

df_work_tidy_simp_B <- df_work_tidy_simp_B %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  summarise(
    across(everything(), mean)
  ) %>% 
  ungroup()
`summarise()` has grouped output by 'correlacion', 'n'. You can override using the `.groups` argument.
df_work_tidy_simp_B

4.5 Format tidy data

4.6 Plots

plot_assess_A <- df_work_tidy_simp %>%
  mutate(
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50"))
  ) %>% 
  filter(correlacion != "0.50") %>% 
  ggplot(aes(x = Tipo_Sim, y = Valor,
             # colour = Ajuste,
             shape = Ajuste,
             linetype = Ajuste,
             group = Ajuste)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(-0.5, 5.5),
                     breaks = seq(-0.5, 5.5, 1)) +
  labs(title = "",
       x = "Condiciones de Simulación",
       y = "") +
  # scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  facet_grid(correlacion ~ n) +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 90),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

plot_assess_B <- df_work_tidy_simp %>%
  mutate(
    correlacion = factor(correlacion, 
                         labels = c("0.12", "0.20",
                                    "0.31", "0.50"))
  ) %>% 
  filter(correlacion != "0.50") %>% 
  ggplot(aes(x = Tipo_Sim, y = Valor,
             # colour = Ajuste,
             shape = Ajuste,
             linetype = Ajuste,
             group = Ajuste)) +
  geom_point(color = "#3a3a3a", size = 2) +
  geom_path(color = "#3a3a3a") +
  scale_y_continuous(limits = c(-0.5, 5.5),
                     breaks = seq(-0.5, 5.5, 1)) +
  labs(title = "",
       x = "Condiciones de Simulación",
       y = "") +
  # scale_x_discrete(guide = guide_axis(n.dodge = 2)) +
  facet_grid(n ~ correlacion) +
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5,
                              size = 12,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 9,
      face="plain",
      colour="black"),
    axis.text.x = element_text(angle = 90),
    axis.title.x = element_text(
      size = 11,
      margin = margin(t = 7, r = 0, b = 0, l = 0)
    ),
    strip.text = element_text(
      size = 11
    ),
    legend.title = element_blank(),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=10),
    panel.spacing = unit(0.8, "lines")
  ) 

5 Evaluate normality

5.1 Calculation of kurtosis and skewness for each variable

library(e1071)

Attaching package: 㤼㸱e1071㤼㸲

The following object is masked from 㤼㸱package:semTools㤼㸲:

    kurtosis
df_work_tidy_evaluate <- df_work_tidy %>% 
  mutate(
    kurtosis_v1 = map_dbl(Data,
                          ~ kurtosis(.x$V1, type = 2)),
    kurtosis_v2 = map_dbl(Data,
                          ~ kurtosis(.x$V2, type = 2)),
    skewness_v1 = map_dbl(Data,
                          ~ skewness(.x$V1, type = 2)),
    skewness_v2 = map_dbl(Data,
                          ~ skewness(.x$V2, type = 2))
  ) %>% 
  select(-c(cort_pears:coef_winso))

df_work_tidy_evaluate

5.2 Calculation evaluating multivariate normality

5.2.1 Settings multicore

library(multidplyr)

if (Sys.getenv("RSTUDIO") == "1" && !nzchar(Sys.getenv("RSTUDIO_TERM")) && 
    (Sys.info()["sysname"] == "Darwin" || Sys.info()["sysname"] == "Linux") && 
    getRversion() >= "4.0.0") {
  parallel:::setDefaultClusterOptions(setup_strategy = "sequential")
}

cluster <- new_cluster(parallel::detectCores())

5.2.2 Evaluation

df_work_tidy_evaluate <- df_work_tidy_evaluate %>% 
  partition(cluster) %>% 
  mutate(
    Normal_multi_r = purrr::map_chr(Data,
                             ~ MVN::mvn(.x)$multivariateNormality$Result[3]),
    Normal_multi_r = ifelse(Normal_multi_r == "YES", "Si", "No")
  ) %>% 
  collect()

5.2.3 Categorize by kurtosis and skewness

df_work_tidy_evaluate <- df_work_tidy_evaluate %>% 
  mutate(
    norm_uni = ifelse(kurtosis_v1 >= - 1.5 & kurtosis_v1 <= 1.5 &
                        skewness_v1 >= - 1.5 & skewness_v1 <= 1.5 &
                        kurtosis_v2 >= - 1.5 & kurtosis_v2 <= 1.5 &
                        skewness_v2 >= - 1.5 & skewness_v2 <= 1.5, 
                      "Si", "No")
  )

5.3 Format tidy data

5.4 Data format for evaluation

Complete:

df_work_tidy_A <- df_work_tidy_evaluate %>% 
  select(correlacion:Tipo_Sim, Normal_multi_r:norm_uni) %>%
  pivot_longer(
    cols = Normal_multi_r:norm_uni,
    names_to = "Evaluación Normalidad",
    values_to = "Dx"
  ) %>%
  mutate(
    `Evaluación Normalidad` = ifelse(`Evaluación Normalidad` == "Normal_multi_r",
                                     "Normalidad mardia", "Normalidad As y Ks")
  )

Grouped:

df_work_tidy_simp_B <- df_work_tidy_evaluate %>%
  mutate(
    Tipo_Sim = fct_collapse(Tipo_Sim,
                            "MVN" = "MVN",
                            "MVN OL M3" = "OL M3",
                            "MVN OL M6" = "OL M6",
                            "MVN OL M3V" = c("OL M3 V1", "OL M3 V2", "OL M3 V3"),
                            "MVN OL M6V" = c("OL M6 V1", "OL M6 V2", "OL M6 V3"),
                            "No-MVN" = c("No-MVN A", "No-MVN C", "No-MVN D"),
                            "No-MVN ks+" = c("No-MVN B", "No-MVN E")
    )
  ) %>%
  select(correlacion:Tipo_Sim, Normal_multi_r:norm_uni) %>%
  pivot_longer(
    cols = Normal_multi_r:norm_uni,
    names_to = "Evaluación Normalidad",
    values_to = "Dx"
  ) %>%
  mutate(
    `Evaluación Normalidad` = ifelse(`Evaluación Normalidad` == "Normal_multi_r",
                                     "Normalidad mardia", "Normalidad As y Ks")
  )

5.5 Plots

5.5.1 Plot Mardia full

Calculate the percentage of dataframes identified as multivariate normal in each condition.

df_work_tidy_A_mardia <- df_work_tidy_A %>% 
  filter(`Evaluación Normalidad` == "Normalidad mardia") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

df_work_tidy_A_mardia

Plot generation:

plot_A_mardia <- df_work_tidy_A_mardia %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 
Using alpha for a discrete variable is not advised.

5.5.2 Plot Skewness and Kurtosis full

Calculate the percentage of dataframes identified as univariate normality in each condition.

df_work_tidy_A_as_ks <- df_work_tidy_A %>% 
  filter(`Evaluación Normalidad` == "Normalidad As y Ks") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot generation:

plot_A_as_ks <- df_work_tidy_A_as_ks %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 
Using alpha for a discrete variable is not advised.

5.5.3 Plot Mardia grouped

Calculate the percentage of dataframes identified as multivariate normal in each condition.

df_work_tidy_B_mardia <- df_work_tidy_simp_B %>% 
  filter(`Evaluación Normalidad` == "Normalidad mardia") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot generation:

plot_B_mardia <- df_work_tidy_B_mardia %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 
Using alpha for a discrete variable is not advised.

5.5.4 Plot Skewness and Kurtosis grouped

Calculate the percentage of dataframes identified as univariate normality in each condition.

df_work_tidy_B_as_ks <- df_work_tidy_simp_B %>% 
  filter(`Evaluación Normalidad` == "Normalidad As y Ks") %>% 
  count(correlacion, n, Tipo_Sim,
        Dx, name = "Cantidad") %>% 
  group_by(correlacion, n, Tipo_Sim) %>% 
  mutate(Porcentaje = Cantidad/sum(Cantidad)) %>% 
  select(-Cantidad) %>% 
  pivot_wider(
    names_from = Dx,
    values_from = Porcentaje,
    values_fill = 0
  ) %>% 
  ungroup()

Plot Generation:

plot_B_as_ks <- df_work_tidy_B_as_ks %>% 
  mutate(correlacion = factor(correlacion,
                              labels = c("0.12", "0.20",
                                         "0.31", "0.50")),
         correlacion = fct_rev(correlacion)) %>% 
  ggplot(aes(x = Si, y = correlacion,
             alpha = correlacion, label = scales::percent(Si, 
                                                          accuracy = 1))) +
  geom_col() +
  facet_grid(n ~ Tipo_Sim)  +
  scale_alpha_discrete(
    name = "Correlación",
    guide = guide_legend(reverse = TRUE)
  ) + 
  scale_x_continuous(
    limits = c(0, 1),
    breaks = c(0, 0.25, 0.50, 0.75, 1),
    labels = scales::percent_format(),
    expand = c(0, 0.1),
    guide = guide_axis(n.dodge = 2)
  ) +
  geom_label(
    size = 3.5,
    label.size = 0.25, 
    label.r = unit(0.15, "lines"),
    label.padding = unit(0.15, "lines"),
    position = position_stack(vjust = 0.5),
    show.legend = FALSE
  ) +
  labs(
    y = "",
    x = ""
  ) + 
  theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5),
    text = element_text(
      size = 11,
      face="bold"), 
    axis.text = element_text(
      size = 11,
      face="plain",
      colour="black"),
    legend.title = element_text(
      size = 11,
      face = "bold"
    ),
    legend.text = element_text(
      face="plain",
      colour="black",
      size=11),
    strip.text = element_text(
      face="plain",
      colour="black",
      size=11),
    panel.spacing = unit(0.6, "lines")
  ) 
Using alpha for a discrete variable is not advised.

LS0tDQp0aXRsZTogIlNpbXVsYXRpb24gb2YgY29ycmVsYXRpb24gZXN0aW1hdG9ycyBmb3Igbm9ybWFsIGFuZCBub24tbm9ybWFsIGNvcnJlbGF0aW9ucyINCmRhdGU6ICIwMy8wNC8yMDIxIg0KYXV0aG9yOg0KICAtIG5hbWU6IEpvc8OpIFZlbnR1cmEtTGXDs24NCiAgICBlbWFpbDogam9zZS52ZW50dXJhQHVwbi5wZQ0KICAgIGFmZmlsaWF0aW9uOiBVbml2ZXJzaWRhZCBQcml2YWRhIGRlbCBOb3J0ZQ0KICAtIG5hbWU6IEJyaWFuIE4uIFBlw7FhLUNhbGVybw0KICAgIGVtYWlsOiBicmlhbm1zbUBnbWFpbC5jb20NCiAgICBhZmZpbGlhdGlvbjogR3J1cG8gZGUgRXN0dWRpb3MgQXZhbmNlcyBlbiBNZWRpY2nDs24gUHNpY29sw7NnaWNhLCBVbml2ZXJzaWRhZCBOYWNpb25hbCBNYXlvciBkZSBTYW4gTWFyY29zLCBMaW1hLCBQZXLDug0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazogDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgaGlnaGxpZ2h0OiBrYXRlDQogICAgdGhlbWU6IGZsYXRseQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgUHJlcGFyYXRpb25zIGZvciBhbmFseXNpcw0KDQpMb2FkaW5nIHBhY2thZ2VzIHRvIHNpbXVsYXRlIGFuZCBtYW5pcHVsYXRlIGRhdGEuIA0KDQpgYGB7cn0NCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCg0KIyBTaW11bGF0ZSBkYXRhDQoNCkRhdGEgZ2VuZXJhdGlvbiB3YXMgcGVyZm9ybWVkIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6DQoNCi0gQ29ycmVsYXRpb25zOiAwLjEyLCAwLjIwLCAwLjMxLCAwLjUwDQotIFNhbXBsZSBzaXplczogNTAsIDEwMCwgMjUwLCA1MDAsIDEwMDANCi0gTnVtYmVyIG9mIHJlcGxpY2F0aW9uczogMTAwMA0KDQpJbiB0aGlzIHdheSwgMjAgKmRhdGFmcmFtZXMqIGFyZSBnZW5lcmF0ZWQgd2l0aCBkaWZmZXJlbnQgYW1vdW50cyBvZiBkYXRhIHdpdGhpbiBlYWNoIG9mIHRoZW0sIHdoaWNoIHdpbGwgaGF2ZSAxLDAwMCAqcmVwbGljYXRpb25zKi4gSW4gdG90YWwsIDIwLDAwMCAqZGF0YWZyYW1lcyogd2l0aCBvYnNlcnZhdGlvbnMgZm9yIGFuYWx5c2lzLg0KDQoNCiMjIEdlbmVyYXRlIG1hdHJpY2VzIGFuZCBvYnNlcnZhdGlvbnMNCg0KQ3JlYXRlIHRoZSB2YXJpYWJsZXMgdGhhdCBpbmRpY2F0ZSB0aGUgY29uZGl0aW9ucw0KDQpgYGB7cn0NCnNldC5zZWVkKDIwMjApIA0KciA8LSBjKDAuMTIsIDAuMjAsIDAuMzEsIDAuNTApICMjIENvcnJlbGF0aW9ucyANCm4gPC0gYyg1MCwgMTAwLCAyNTAsIDUwMCwgMTAwMCkgIyMgU2FtcGxlIHNpemVzDQpyZXBsaWMgPC0gMTAwMA0KYGBgDQoNCg0KYGBge3J9DQpzaWdtYSA8LSBsaXN0KCkNCmZvciAoaSBpbiBzZXFfYWxvbmcocikpIHsgDQogIHNpZ21hW1tpXV0gPC0gbWF0cml4KGRhdGEgPSBjKDEsIHJlcChyW2ldLCAyKSwgMSksDQogICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLA0KICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMikNCn0NCg0KDQojIEdlbmVyYXIgbG9zIGRhdG9zIGRlIGNvcnJlbGFjacOzbg0KZGZfY29yIDwtIGxpc3QoKQ0KZm9yIChpIGluIHNlcV9hbG9uZyhzaWdtYSkpIHsNCiAgZGZfY29yW1tpXV0gPC0gbGlzdCgpDQogIGZvciAoaiBpbiBzZXFfYWxvbmcobikpIHsNCiAgICBkZl9jb3JbW2ldXVtbal1dIDwtIGxpc3QoKQ0KICAgIGZvciAoayBpbiAxOnJlcGxpYykgew0KICAgICAgZGZfY29yW1tpXV1bW2pdXVtba11dIDwtIG12cm5vcm0obiAgICAgPSBuW2pdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgICAgPSByZXAoMCwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IHNpZ21hW1tpXV0pICU+JSANCiAgICAgICAgYXNfdGliYmxlKCkNCiAgICB9DQogIH0NCn0NCmBgYA0KDQojIyBGb3JtYXQgdGhlIGRhdGEgYXMgZGF0YWZyYW1lIC8gdGliYmxlcw0KDQpXZSB3aWxsIGFzc2VtYmxlIHRoZSBsaXN0IG9iamVjdCBpbiBzdWNoIGEgd2F5IHRoYXQgd2UgY2FuIGlkZW50aWZ5IGJ5IGNvbHVtbnMgdGhlIGNvcnJlbGF0aW9uLCBzYW1wbGUgc2l6ZSBhbmQgcmVwbGljYXRlIG51bWJlciBvZiBlYWNoIG9ic2VydmF0aW9uLg0KDQpgYGB7cn0NCiMgVW5pciBsb3MgZGF0b3MgeSBwYXNhcmxvIGEgZm9ybWF0byB0aWR5DQp0ZW1wIDwtIGRmX2Nvcg0KZGZfY29yIDwtIGxpc3QoKQ0KZm9yIChpIGluIHNlcV9hbG9uZyhzaWdtYSkpIHsNCiAgZGZfY29yW1tpXV0gPC0gbGlzdCgpDQogIGZvciAoaiBpbiBzZXFfYWxvbmcobikpIHsNCiAgICBkZl9jb3JbW2ldXVtbal1dIDwtIHRlbXBbW2ldXVtbal1dICU+JSANCiAgICAgIGJpbmRfcm93cyguaWQgPSAicmVwbGljIikgJT4lIA0KICAgICAgbXV0YXRlKHJlcGxpYyA9IGFzLm51bWVyaWMocmVwbGljKSkNCiAgfQ0KICBkZl9jb3JbW2ldXSA8LSBkZl9jb3JbW2ldXSAlPiUgDQogICAgYmluZF9yb3dzKC5pZCA9ICJuIikgJT4lIA0KICAgIG11dGF0ZShuID0gcmVjb2RlKG4sICIxIiA9IDUwLCAiMiIgPSAxMDAsDQogICAgICAgICAgICAgICAgICAgICAgIjMiID0gMjUwLCAiNCIgPSA1MDAsIA0KICAgICAgICAgICAgICAgICAgICAgICI1IiA9IDEwMDApKQ0KfQ0KDQpkZl9jb3IgPC0gZGZfY29yICU+JSANCiAgYmluZF9yb3dzKC5pZCA9ICJjb3JyZWxhY2lvbiIpICU+JSANCiAgbXV0YXRlKGNvcnJlbGFjaW9uID0gcmVjb2RlKGNvcnJlbGFjaW9uLCAiMSIgPSAwLjEyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIiID0gMC4yMCwgIjMiID0gMC4zMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI0IiA9IDAuNTApKSAlPiUgDQogIGFycmFuZ2UoY29ycmVsYWNpb24sIG4sIHJlcGxpYykNCg0KIyBDcmVhciBkYXRhIG5lc3QNCmRmX25lc3QgPC0gZGZfY29yICU+JSANCiAgbmVzdChkYXRhID0gYyhWMSwgVjIpKQ0KDQpybSh0ZW1wLCBpLCBqLCBrKQ0KYGBgDQoNCiMjIEFkZCBvdXRsaWVycyANCg0KRml2ZSBwZXJjZW50IG9mIHRoZSBkYXRhIGluIGVhY2ggZGF0YSBmcmFtZSB3aWxsIGJlIHJhbmRvbWx5IHJlcGxhY2VkIGJ5IG91dGxpZXIgY29ycmVsYXRpb25zIGRpZmZlcmVudCBmcm9tIHRoZSBvbmUgZ2VuZXJhdGVkLiBGb3IgZXhhbXBsZSwgaW4gdGhlIGNhc2Ugb2YgYSBkYXRhZnJhbWUgd2l0aCBhIGNvcnJlbGF0aW9uIG9mIDAuMTIgYW5kIGEgc2FtcGxlIHNpemUgb2YgNTAsIDMgcGFpcnMgb2YgY29ycmVsYXRpb25zIHdpbGwgYmUgcmFuZG9tbHkgcmVwbGFjZWQgd2l0aCAzIHBhaXJzIG9mIGNvcnJlbGF0aW9ucyBnZW5lcmF0ZWQgd2l0aCBjb3JyZWxhdGlvbnMgb2YgMC4yMCwgMC4zMSBhbmQgMC41MC4NCg0KYGBge3J9DQojIEFkZCB0aGUgbnVtYmVyIG9mIG91dGxpZXJzIHRvIGJlIGFkZGVkIGFuZCB0aGVpciBsb2NhdGlvbnMgT3V0bGllcnMgYXQgNSUuDQpkZl93b3JrIDwtIGRmX25lc3QgJT4lIA0KICByb3d3aXNlKCkgJT4lIA0KICBtdXRhdGUoDQogICAgcmF0aW9fb3V0bGllciA9IG1hcF9kYmwobiwNCiAgICAgICAgICAgICAgICAgICAgICAgIH4gY2VpbGluZygwLjA1Km4pKSwNCiAgICBwb3NpY2lfcmVwX20zID0gbWFwMihuLCByYXRpb19vdXRsaWVyLA0KICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksDQogICAgcG9zaWNpX3JlcF9tNiA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwNCiAgICAgICAgICAgICAgICAgICAgICAgICB+IHNhbXBsZSgxOi54LCAueSkpLA0KICAgIHBvc2ljaV9yZXBfbTN2MSA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwNCiAgICBwb3NpY2lfcmVwX20zdjIgPSBtYXAyKG4sIHJhdGlvX291dGxpZXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksDQogICAgcG9zaWNpX3JlcF9tM3YzID0gbWFwMihuLCByYXRpb19vdXRsaWVyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB+IHNhbXBsZSgxOi54LCAueSkpLA0KICAgIHBvc2ljaV9yZXBfbTZ2MSA9IG1hcDIobiwgcmF0aW9fb3V0bGllciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2FtcGxlKDE6LngsIC55KSksDQogICAgcG9zaWNpX3JlcF9tNnYyID0gbWFwMihuLCByYXRpb19vdXRsaWVyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgfiBzYW1wbGUoMToueCwgLnkpKSwNCiAgICBwb3NpY2lfcmVwX202djMgPSBtYXAyKG4sIHJhdGlvX291dGxpZXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB+IHNhbXBsZSgxOi54LCAueSkpDQogICkNCg0KIyBBZGQgY29ycmVsYXRpb25zIHRoYXQgd2VyZSBub3QgY29uc2lkZXJlZA0KZGZfd29yayA8LSBkZl93b3JrICU+JSANCiAgbXV0YXRlKA0KICAgIGNvcnJlbGFfYSA9IHJbd2hpY2goY29ycmVsYWNpb24gIT0gcilbMV1dLA0KICAgIGNvcnJlbGFfYiA9IHJbd2hpY2goY29ycmVsYWNpb24gIT0gcilbMl1dLA0KICAgIGNvcnJlbGFfYyA9IHJbd2hpY2goY29ycmVsYWNpb24gIT0gcilbM11dDQogICkNCmBgYA0KDQpPbiB0aGUgY29ycmVsYXRpb25zIGlkZW50aWZpZWQgdG8gYmUgZ2VuZXJhdGVkLCB0aGUgZGF0YSBtYXRyaXggbmVjZXNzYXJ5IGZvciB0aGUgbXVsdGl2YXJpYXRlIHNpbXVsYXRpb24gaXMgY3JlYXRlZCBhcyBhbiBvdXRsaWVyLg0KDQpgYGB7cn0NCmRmX3dvcmsgPC0gZGZfd29yayAlPiUgDQogIG11dGF0ZSgNCiAgICBtYXRyaXggPSBtYXAoY29ycmVsYWNpb24sDQogICAgICAgICAgICAgICAgIH4gbWF0cml4KGRhdGEgPSByZXAoYygxLCByZXAoLngsIDIpKSwgMiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpKSwNCiAgICBtYXRyaXhfYSA9IG1hcChjb3JyZWxhX2EsDQogICAgICAgICAgICAgICAgICAgfiBtYXRyaXgoZGF0YSA9IHJlcChjKDEsIHJlcCgueCwgMikpLCAyKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpKSwNCiAgICBtYXRyaXhfYiA9IG1hcChjb3JyZWxhX2IsDQogICAgICAgICAgICAgICAgICAgfiBtYXRyaXgoZGF0YSA9IHJlcChjKDEsIHJlcCgueCwgMikpLCAyKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpKSwNCiAgICBtYXRyaXhfYyA9IG1hcChjb3JyZWxhX2MsDQogICAgICAgICAgICAgICAgICAgfiBtYXRyaXgoZGF0YSA9IHJlcChjKDEsIHJlcCgueCwgMikpLCAyKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpKQ0KICApICU+JSANCiAgdW5ncm91cCgpDQpgYGANCg0KQWdncmVnYXRlIG91dGxpZXJzIGFyZSBvZiAyIHR5cGVzOiB0aGV5IHZhcnkgb25seSBieSB0aGUgbWVhbiBhbmQgdGhleSB2YXJ5IGJ5IHRoZSBtZWFuIGFuZCBpdHMgbWF0cml4Og0KDQotIG91dGxpZXJfbTM6IFZhcmllcyBieSBhbiBtZWFuIG9mIDMgDQotIG91dGxpZXJfbTY6IFZhcmllcyBieSBhbiBtZWFuIG9mIDYNCi0gb3V0bGllcl9tM3YxOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiAzIGFuZCBtYXRyaXggYQ0KLSBvdXRsaWVyX20zdjI6IFZhcmllcyBieSBhbiBtZWFuIG9mIDMgYW5kIG1hdHJpeCBiDQotIG91dGxpZXJfbTN2MzogVmFyaWVzIGJ5IGFuIG1lYW4gb2YgMyBhbmQgbWF0cml4IGMNCi0gb3V0bGllcl9tNnYxOiBWYXJpZXMgYnkgYW4gbWVhbiBvZiA2IGFuZCBtYXRyaXggYQ0KLSBvdXRsaWVyX202djI6IFZhcmllcyBieSBhbiBtZWFuIG9mIDYgYW5kIG1hdHJpeCBiDQotIG91dGxpZXJfbTZ2MzogVmFyaWVzIGJ5IGFuIG1lYW4gb2YgNiBhbmQgbWF0cml4IGMNCg0KYGBge3J9DQpzZXQuc2VlZCgyMDE5KSANCg0KZGZfd29yayA8LSBkZl93b3JrICU+JSANCiAgbXV0YXRlKA0KICAgIG91dGxpZXJfbTMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeCwgDQogICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ICAgID0gcmVwKDMsIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IC55KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksDQogICAgb3V0bGllcl9tNiA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4LA0KICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ybShuICAgICA9IC54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpLA0KICAgIG91dGxpZXJfbTN2MSA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4X2EsIA0KICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgICAgPSByZXAoMywgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksDQogICAgb3V0bGllcl9tM3YyID0gbWFwMihyYXRpb19vdXRsaWVyLCBtYXRyaXhfYiwgDQogICAgICAgICAgICAgICAgICAgICAgICB+IG12cm5vcm0obiAgICAgPSAueCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCgzLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IC55KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpKSwNCiAgICBvdXRsaWVyX20zdjMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9jLCANCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ybShuICAgICA9IC54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ICAgID0gcmVwKDMsIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpLA0KICAgIG91dGxpZXJfbTZ2MSA9IG1hcDIocmF0aW9fb3V0bGllciwgbWF0cml4X2EsIA0KICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub3JtKG4gICAgID0gLngsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgICAgPSByZXAoNiwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksDQogICAgb3V0bGllcl9tNnYyID0gbWFwMihyYXRpb19vdXRsaWVyLCBtYXRyaXhfYiwgDQogICAgICAgICAgICAgICAgICAgICAgICB+IG12cm5vcm0obiAgICAgPSAueCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSAgICA9IHJlcCg2LCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IC55KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpKSwNCiAgICBvdXRsaWVyX202djMgPSBtYXAyKHJhdGlvX291dGxpZXIsIG1hdHJpeF9jLCANCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ybShuICAgICA9IC54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ICAgID0gcmVwKDYsIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnkpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXNfdGliYmxlKCkpDQogICkNCmBgYA0KDQpUaGVzZSBuZXcgc2ltdWxhdGVkIG91dGxpZXIgY29ycmVsYXRpb25zIHdpbGwgYmUgaW5zZXJ0ZWQgaW50byB0aGUgaW5pdGlhbGx5IGNhbGN1bGF0ZWQgcmFuZG9tIHBvc2l0aW9ucyBpbiBlYWNoIGRhdGFmcmFtZS4NCg0KYGBge3J9DQpkZl93b3JrIDwtIGRmX3dvcmsgJT4lIA0KICBtdXRhdGUoDQogICAgZGF0YV9vdXRfbTMgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tMywgb3V0bGllcl9tMyksDQogICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwNCiAgICBkYXRhX291dF9tNiA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX202LCBvdXRsaWVyX202KSwNCiAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLA0KICAgIGRhdGFfb3V0X20zdjEgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tM3YxLCBvdXRsaWVyX20zdjEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoLi4zKSksDQogICAgZGF0YV9vdXRfbTN2MiA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX20zdjIsIG91dGxpZXJfbTN2MiksDQogICAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwNCiAgICBkYXRhX291dF9tM3YzID0gcG1hcChsaXN0KGRhdGEsIHBvc2ljaV9yZXBfbTN2Mywgb3V0bGllcl9tM3YzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpLA0KICAgIGRhdGFfb3V0X202djEgPSBwbWFwKGxpc3QoZGF0YSwgcG9zaWNpX3JlcF9tNnYxLCBvdXRsaWVyX202djEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIH4gLi4xICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlKC0gLi4yKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoLi4zKSksDQogICAgZGF0YV9vdXRfbTZ2MiA9IHBtYXAobGlzdChkYXRhLCBwb3NpY2lfcmVwX202djIsIG91dGxpZXJfbTZ2MiksDQogICAgICAgICAgICAgICAgICAgICAgICAgfiAuLjEgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2UoLSAuLjIpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmRfcm93cyguLjMpKSwNCiAgICBkYXRhX291dF9tNnYzID0gcG1hcChsaXN0KGRhdGEsIHBvc2ljaV9yZXBfbTZ2Mywgb3V0bGllcl9tNnYzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC4uMSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSgtIC4uMikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKC4uMykpDQogICkNCmBgYA0KDQpBZGRpdGlvbmFsbHksIG5ldyBkYXRhZnJhbWVzIHdpdGggdGhlIHNhbWUgY29ycmVsYXRpb24gY29uZGl0aW9ucywgc2FtcGxlIHNpemUgYW5kIG51bWJlciBvZiByZXBsaWNhdGlvbnMgd2l0aCBub24tbm9ybWFsIGRhdGEgZGlzdHJpYnV0aW9ucyBhcmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBhbGdvcml0aG0gb2YgVmFsZSBhbmQgTWF1cmVsbGkgKDE5ODMpLiANCg0KTm9uLW5vcm1hbGl0eSBjb25kaXRpb25zIHdlcmUgZ2VuZXJhdGVkIG9uIHRoZSBiYXNpcyBvZiB0aGUgd29yayBvZiBbU2hlbmcgJiBTaGVuZyAoMjAxMildKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzMyNzk3MjQvKToNCg0KLSBza2V3bmVzcyA9IDAuMDAsIGt1cnRvc2lzID0g4oiSIDEuMzg1IChzeW1tZXRyaWMgcGxhdHlrdXJ0aWMgZGlzdHJpYnV0aW9uKTsNCi0gc2tld25lc3MgPSAwLjAwLCBrdXJ0b3NpcyA9IDI1IChzeW1tZXRyaWMgbGVwdG9rdXJ0aWMgZGlzdHJpYnV0aW9uKTsNCi0gc2tld25lc3MgPSAwLjk2LCBrdXJ0b3NpcyA9IDAuMTMgKG5vbi1zeW1tZXRyaWMgZGlzdHJpYnV0aW9uKTsNCi0gc2tld25lc3MgPSAwLjQ4LCBrdXJ0b3NpcyA9IOKIkiAwLjkyIChub24tc3ltbWV0cmljIHBsYXR5a3VydGljIGRpc3RyaWJ1dGlvbik7DQotIHNrZXduZXNzID0gMi41MCwga3VydG9zaXMgPSAyNSAobm9uLXN5bW1ldHJpYyBsZXB0b2t1cnRpYyBkaXN0cmlidXRpb24pLg0KDQpgYGB7cn0NCnNldC5zZWVkKDIwMjEpIA0KbGlicmFyeShzZW1Ub29scykNCg0KZGZfd29yayA8LSBkZl93b3JrICU+JSANCiAgbXV0YXRlKA0KICAgIGRhdGFfbm9ub3JtMSA9IG1hcDIobiwgbWF0cml4LA0KICAgICAgICAgICAgICAgICAgICAgICAgfiBtdnJub25ub3JtKG4gPSAueCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdSA9IHJlcCgwLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaWdtYSA9IC55LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNrZXduZXNzID0gYygwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrdXJ0b3NpcyA9IGMoLTEuMzg1KSkgJT4lICMgc3ltbWV0cmljIHBsYXR5a3VydGljIGRpc3RyaWJ1dGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksDQogICAgZGF0YV9ub25vcm0yID0gbWFwMihuLCBtYXRyaXgsDQogICAgICAgICAgICAgICAgICAgICAgICB+IG12cm5vbm5vcm0obiA9IC54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ID0gcmVwKDAsIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3MgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gMjUpICU+JSAjIHN5bW1ldHJpYyBsZXB0b2t1cnRpYyBkaXN0cmlidXRpb24gDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpKSwNCiAgICBkYXRhX25vbm9ybTMgPSBtYXAyKG4sIG1hdHJpeCwNCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ubm9ybShuID0gLngsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgPSByZXAoMCwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IDAuOTYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga3VydG9zaXMgPSAwLjEzKSAlPiUgIyBub24tc3ltbWV0cmljIGRpc3RyaWJ1dGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSksDQogICAgZGF0YV9ub25vcm00ID0gbWFwMihuLCBtYXRyaXgsDQogICAgICAgICAgICAgICAgICAgICAgICB+IG12cm5vbm5vcm0obiA9IC54LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11ID0gcmVwKDAsIDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNpZ21hID0gLnksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3MgPSAwLjQ4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGt1cnRvc2lzID0gLTAuOTIpICU+JSAjIG5vbi1zeW1tZXRyaWMgcGxhdHlrdXJ0aWMgZGlzdHJpYnV0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFzX3RpYmJsZSgpKSwNCiAgICBkYXRhX25vbm9ybTUgPSBtYXAyKG4sIG1hdHJpeCwNCiAgICAgICAgICAgICAgICAgICAgICAgIH4gbXZybm9ubm9ybShuID0gLngsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXUgPSByZXAoMCwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAueSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2V3bmVzcyA9IDIuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrdXJ0b3NpcyA9IDI1KSAlPiUgIyBub24tc3ltbWV0cmljIGxlcHRva3VydGljIGRpc3RyaWJ1dGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgICBhc190aWJibGUoKSkNCiAgKQ0KYGBgDQoNCkZpbmFsbHksIHRoZSB2YXJpYWJsZXMgdGhhdCB3aWxsIG5vIGxvbmdlciBiZSB1c2VkIGFyZSBlbGltaW5hdGVkLg0KDQpgYGB7cn0NCmRmX3dvcmsgPC0gZGZfd29yayAlPiUgDQogIHNlbGVjdCgtYyhyYXRpb19vdXRsaWVyOm91dGxpZXJfbTZ2MykpDQoNCmRmX3dvcmsNCmBgYA0KDQoNCiMgQ2FsY3VsYXRpb24gb2YgY29ycmVsYXRpb25zDQoNCiMjIEZvcm1hdCB0aWR5IGRhdGENCmBgYHtyfQ0KZGZfd29ya190aWR5IDwtIGRmX3dvcmsgJT4lIA0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGRhdGE6ZGF0YV9ub25vcm01LA0KICAgIG5hbWVzX3RvID0gIlRpcG9fU2ltIiwNCiAgICB2YWx1ZXNfdG8gPSAiRGF0YSINCiAgKQ0KYGBgDQoNCiMjIENvcnJlbGF0aW9ucw0KDQpgYGB7cn0NCmxpYnJhcnkoV1JTMikNCmRmX3dvcmtfdGlkeSA8LSBkZl93b3JrX3RpZHkgJT4lIA0KICBtdXRhdGUoDQogICAgY29ydF9wZWFycyA9IG1hcChEYXRhLA0KICAgICAgICAgICAgICAgICAgICAgfiBjb3IudGVzdCgueCRWMSwgLngkVjIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIikpLA0KICAgIGNvcnRfc3BlYXIgPSBtYXAoRGF0YSwNCiAgICAgICAgICAgICAgICAgICAgIH4gY29yLnRlc3QoLngkVjEsIC54JFYyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3BlYXJtYW4iKSksDQogICAgY29ydF93aW5zbyA9IG1hcChEYXRhLA0KICAgICAgICAgICAgICAgICAgICAgfiB3aW5jb3IoLngkVjEsIC54JFYyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHIgPSAwLjIpKQ0KICApDQpgYGANCg0KIyMgT2J0YWluIHRoZSBjb2VmZmljaWVudHMNCg0KYGBge3J9DQpkZl93b3JrX3RpZHkgPC0gZGZfd29ya190aWR5ICU+JSANCiAgbXV0YXRlKA0KICAgIGNvZWZfcGVhcnMgPSBtYXBfZGJsKGNvcnRfcGVhcnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgfiAueCRlc3RpbWF0ZVsxXSksDQogICAgY29lZl9zcGVhciA9IG1hcF9kYmwoY29ydF9zcGVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICB+IC54JGVzdGltYXRlWzFdKSwNCiAgICBjb2VmX3dpbnNvID0gbWFwX2RibChjb3J0X3dpbnNvLA0KICAgICAgICAgICAgICAgICAgICAgICAgIH4gLngkY29yWzFdKQ0KICApDQoNCmRmX3dvcmtfdGlkeV9zaW1wIDwtIGRmX3dvcmtfdGlkeSAlPiUgDQogIHNlbGVjdCgtYyhEYXRhOmNvcnRfd2luc28pKQ0KYGBgDQoNCiMgRXZhbHVhdGUgc2ltdWxhdGlvbg0KDQojIyBDYWxjdWxhdGUgUk1TRUEgYW5kIEJpYXMNCg0KYGBge3J9DQpkZl93b3JrX3RpZHlfc2ltcCA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUgDQogIHJvd3dpc2UoKSAlPiUgDQogIG11dGF0ZSgNCiAgICBkaWZfcGVhcnMgPSAoY29lZl9wZWFycyAtIGNvcnJlbGFjaW9uKS9jb3JyZWxhY2lvbiwNCiAgICBkaWZfc3BlYXIgPSAoY29lZl9zcGVhciAtIGNvcnJlbGFjaW9uKS9jb3JyZWxhY2lvbiwNCiAgICBkaWZfd2luc28gPSAoY29lZl93aW5zbyAtIGNvcnJlbGFjaW9uKS9jb3JyZWxhY2lvbg0KICApICU+JSANCiAgdW5ncm91cCgpDQoNCmRmX3dvcmtfdGlkeV9zaW1wIDwtIGRmX3dvcmtfdGlkeV9zaW1wICU+JSANCiAgZ3JvdXBfYnkoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltKSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBybXNlYV9wZWFycyA9IHNxcnQoc3VtKGRpZl9wZWFyc14yKS8xMDAwKSwNCiAgICBzZXNnb19wZWFycyA9IChzdW0oZGlmX3BlYXJzKS8xMDAwKSwNCiAgICBybXNlYV9zcGVhciA9IHNxcnQoc3VtKGRpZl9zcGVhcl4yKS8xMDAwKSwNCiAgICBzZXNnb19zcGVhciA9IChzdW0oZGlmX3NwZWFyKS8xMDAwKSwNCiAgICBybXNlYV93aW5zbyA9IHNxcnQoc3VtKGRpZl93aW5zb14yKS8xMDAwKSwNCiAgICBzZXNnb193aW5zbyA9IChzdW0oZGlmX3dpbnNvKS8xMDAwKQ0KICApICU+JSANCiAgdW5ncm91cCgpDQoNCmRmX3dvcmtfdGlkeV9zaW1wDQpgYGANCg0KIyMgUmVjb2RlIHNpbXVsYXRpb24gdHlwZXMNCg0KYGBge3J9DQpkZl93b3JrX3RpZHlfc2ltcCA8LSBkZl93b3JrX3RpZHlfc2ltcCAlPiUgDQogIG11dGF0ZSgNCiAgICBUaXBvX1NpbSA9IGZjdF9yZWNvZGUoVGlwb19TaW0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4iID0gImRhdGEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMiID0gImRhdGFfb3V0X20zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IiA9ICJkYXRhX291dF9tNiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMSIgPSAiZGF0YV9vdXRfbTN2MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMiIgPSAiZGF0YV9vdXRfbTN2MiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyBWMyIgPSAiZGF0YV9vdXRfbTN2MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMSIgPSAiZGF0YV9vdXRfbTZ2MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIgPSAiZGF0YV9vdXRfbTZ2MiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMyIgPSAiZGF0YV9vdXRfbTZ2MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQSIgPSAiZGF0YV9ub25vcm0xIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBCIiA9ICJkYXRhX25vbm9ybTIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEMiID0gImRhdGFfbm9ub3JtMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gRCIgPSAiZGF0YV9ub25vcm00IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBFIiA9ICJkYXRhX25vbm9ybTUiKSwNCiAgICBUaXBvX1NpbSA9IGZjdF9yZWxldmVsKFRpcG9fU2ltLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiIsICJPTCBNMyIsICJPTCBNNiIsICJPTCBNMyBWMSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiwgIk9MIE02IFYxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNNiBWMiIsICJPTCBNNiBWMyIpDQogICkgJT4lIA0KICBhcnJhbmdlKGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkNCmBgYA0KDQojIyBDb21wbGV0ZSB0YWJsZSBhYm91dCBSTVNFQSBhbmQgQmlhcw0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9zaW1wX0EgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lIA0KICByZWxvY2F0ZShjb250YWlucygic2VzZ28iKSwgLmFmdGVyID0gInJtc2VhX3dpbnNvIikNCg0KZGZfd29ya190aWR5X3NpbXBfQQ0KYGBgDQoNCiMjIFJlY2FsY3VsYXRpb24gb2YgUk1TRUEgYW5kIEJpYXMgZ3JvdXBpbmcgY29uZGl0aW9ucw0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9zaW1wX0IgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lDQogIG11dGF0ZSgNCiAgICBUaXBvX1NpbSA9IGZjdF9jb2xsYXBzZShUaXBvX1NpbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiA9ICJNVk4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTMiID0gIk9MIE0zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE02IiA9ICJPTCBNNiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNM1YiID0gYygiT0wgTTMgVjEiLCAiT0wgTTMgVjIiLCAiT0wgTTMgVjMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE02ViIgPSBjKCJPTCBNNiBWMSIsICJPTCBNNiBWMiIsICJPTCBNNiBWMyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4iID0gYygiTm8tTVZOIEEiLCAiTm8tTVZOIEMiLCAiTm8tTVZOIEQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIGtzKyIgPSBjKCJOby1NVk4gQiIsICJOby1NVk4gRSIpDQogICAgKQ0KICApICU+JSANCiAgcmVsb2NhdGUoY29udGFpbnMoInNlc2dvIiksIC5hZnRlciA9ICJybXNlYV93aW5zbyIpDQoNCmRmX3dvcmtfdGlkeV9zaW1wX0IgPC0gZGZfd29ya190aWR5X3NpbXBfQiAlPiUgDQogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikNCiAgKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQpkZl93b3JrX3RpZHlfc2ltcF9CDQpgYGANCg0KIyMgRm9ybWF0IHRpZHkgZGF0YQ0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9zaW1wIDwtIGRmX3dvcmtfdGlkeV9zaW1wICU+JSANCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBybXNlYV9wZWFyczpzZXNnb193aW5zbywNCiAgICBuYW1lc190byA9ICJBanVzdGUiLA0KICAgIHZhbHVlc190byA9ICJWYWxvciINCiAgKSAlPiUgDQogIG11dGF0ZSgNCiAgICBBanVzdGUgPSBmY3RfcmVjb2RlKEFqdXN0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICJSTVNFIFBlYXJzb24iID0gInJtc2VhX3BlYXJzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJSTVNFIFNwZWFybWFuIiA9ICJybXNlYV9zcGVhciIsDQogICAgICAgICAgICAgICAgICAgICAgICAiUk1TRSBXaW5zb3JpemVkIiA9ICJybXNlYV93aW5zbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAiU2VzZ28gUGVhcnNvbiIgPSAic2VzZ29fcGVhcnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIlNlc2dvIFNwZWFybWFuIiA9ICJzZXNnb19zcGVhciIsDQogICAgICAgICAgICAgICAgICAgICAgICAiU2VzZ28gV2luc29yaXplZCIgPSAic2VzZ29fd2luc28iKQ0KICApDQoNCmRmX3dvcmtfdGlkeV9zaW1wDQpgYGANCg0KIyMgUGxvdHMNCg0KDQpgYGB7cn0NCnBsb3RfYXNzZXNzX0EgPC0gZGZfd29ya190aWR5X3NpbXAgJT4lDQogIG11dGF0ZSgNCiAgICBjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjMxIiwgIjAuNTAiKSkNCiAgKSAlPiUgDQogIGZpbHRlcihjb3JyZWxhY2lvbiAhPSAiMC41MCIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gVGlwb19TaW0sIHkgPSBWYWxvciwNCiAgICAgICAgICAgICAjIGNvbG91ciA9IEFqdXN0ZSwNCiAgICAgICAgICAgICBzaGFwZSA9IEFqdXN0ZSwNCiAgICAgICAgICAgICBsaW5ldHlwZSA9IEFqdXN0ZSwNCiAgICAgICAgICAgICBncm91cCA9IEFqdXN0ZSkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjM2EzYTNhIiwgc2l6ZSA9IDIpICsNCiAgZ2VvbV9wYXRoKGNvbG9yID0gIiMzYTNhM2EiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjUsIDUuNSksDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoLTAuNSwgNS41LCAxKSkgKw0KICBsYWJzKHRpdGxlID0gIiIsDQogICAgICAgeCA9ICJDb25kaWNpb25lcyBkZSBTaW11bGFjacOzbiIsDQogICAgICAgeSA9ICIiKSArDQogICMgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpKSArDQogIGZhY2V0X2dyaWQoY29ycmVsYWNpb24gfiBuKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgdGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMSwNCiAgICAgIGZhY2U9ImJvbGQiKSwgDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDksDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSA3LCByID0gMCwgYiA9IDAsIGwgPSAwKQ0KICAgICksDQogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMQ0KICAgICksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KA0KICAgICAgZmFjZT0icGxhaW4iLA0KICAgICAgY29sb3VyPSJibGFjayIsDQogICAgICBzaXplPTEwKSwNCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjgsICJsaW5lcyIpDQogICkgDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWcvRXZhbHVhdGVfY29ycmVsYXRpb25fUk1TRUFfQmlhc19BLnBuZyIpDQpgYGANCg0KYGBge3J9DQpwbG90X2Fzc2Vzc19CIDwtIGRmX3dvcmtfdGlkeV9zaW1wICU+JQ0KICBtdXRhdGUoDQogICAgY29ycmVsYWNpb24gPSBmYWN0b3IoY29ycmVsYWNpb24sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC4zMSIsICIwLjUwIikpDQogICkgJT4lIA0KICBmaWx0ZXIoY29ycmVsYWNpb24gIT0gIjAuNTAiKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFRpcG9fU2ltLCB5ID0gVmFsb3IsDQogICAgICAgICAgICAgIyBjb2xvdXIgPSBBanVzdGUsDQogICAgICAgICAgICAgc2hhcGUgPSBBanVzdGUsDQogICAgICAgICAgICAgbGluZXR5cGUgPSBBanVzdGUsDQogICAgICAgICAgICAgZ3JvdXAgPSBBanVzdGUpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiIzNhM2EzYSIsIHNpemUgPSAyKSArDQogIGdlb21fcGF0aChjb2xvciA9ICIjM2EzYTNhIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC41LCA1LjUpLA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0wLjUsIDUuNSwgMSkpICsNCiAgbGFicyh0aXRsZSA9ICIiLA0KICAgICAgIHggPSAiQ29uZGljaW9uZXMgZGUgU2ltdWxhY2nDs24iLA0KICAgICAgIHkgPSAiIikgKw0KICAjIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKSkgKw0KICBmYWNldF9ncmlkKG4gfiBjb3JyZWxhY2lvbikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgIHRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTEsDQogICAgICBmYWNlPSJib2xkIiksIA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSA5LA0KICAgICAgZmFjZT0icGxhaW4iLA0KICAgICAgY29sb3VyPSJibGFjayIpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMSwNCiAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gNywgciA9IDAsIGIgPSAwLCBsID0gMCkNCiAgICApLA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTENCiAgICApLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIGZhY2U9InBsYWluIiwNCiAgICAgIGNvbG91cj0iYmxhY2siLA0KICAgICAgc2l6ZT0xMCksDQogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC44LCAibGluZXMiKQ0KICApIA0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1nL0V2YWx1YXRlX2NvcnJlbGF0aW9uX1JNU0VBX0JpYXNfQi5wbmciKQ0KYGBgDQoNCiMgRXZhbHVhdGUgbm9ybWFsaXR5DQoNCiMjIENhbGN1bGF0aW9uIG9mIGt1cnRvc2lzIGFuZCBza2V3bmVzcyBmb3IgZWFjaCB2YXJpYWJsZQ0KDQpgYGB7cn0NCmxpYnJhcnkoZTEwNzEpDQoNCmRmX3dvcmtfdGlkeV9ldmFsdWF0ZSA8LSBkZl93b3JrX3RpZHkgJT4lIA0KICBtdXRhdGUoDQogICAga3VydG9zaXNfdjEgPSBtYXBfZGJsKERhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIH4ga3VydG9zaXMoLngkVjEsIHR5cGUgPSAyKSksDQogICAga3VydG9zaXNfdjIgPSBtYXBfZGJsKERhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIH4ga3VydG9zaXMoLngkVjIsIHR5cGUgPSAyKSksDQogICAgc2tld25lc3NfdjEgPSBtYXBfZGJsKERhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2tld25lc3MoLngkVjEsIHR5cGUgPSAyKSksDQogICAgc2tld25lc3NfdjIgPSBtYXBfZGJsKERhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIH4gc2tld25lc3MoLngkVjIsIHR5cGUgPSAyKSkNCiAgKSAlPiUgDQogIHNlbGVjdCgtYyhjb3J0X3BlYXJzOmNvZWZfd2luc28pKQ0KDQpkZl93b3JrX3RpZHlfZXZhbHVhdGUNCmBgYA0KDQojIyBDYWxjdWxhdGlvbiBldmFsdWF0aW5nIG11bHRpdmFyaWF0ZSBub3JtYWxpdHkNCg0KIyMjIFNldHRpbmdzIG11bHRpY29yZQ0KYGBge3J9DQpsaWJyYXJ5KG11bHRpZHBseXIpDQoNCmlmIChTeXMuZ2V0ZW52KCJSU1RVRElPIikgPT0gIjEiICYmICFuemNoYXIoU3lzLmdldGVudigiUlNUVURJT19URVJNIikpICYmIA0KICAgIChTeXMuaW5mbygpWyJzeXNuYW1lIl0gPT0gIkRhcndpbiIgfHwgU3lzLmluZm8oKVsic3lzbmFtZSJdID09ICJMaW51eCIpICYmIA0KICAgIGdldFJ2ZXJzaW9uKCkgPj0gIjQuMC4wIikgew0KICBwYXJhbGxlbDo6OnNldERlZmF1bHRDbHVzdGVyT3B0aW9ucyhzZXR1cF9zdHJhdGVneSA9ICJzZXF1ZW50aWFsIikNCn0NCg0KY2x1c3RlciA8LSBuZXdfY2x1c3RlcihwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkNCmBgYA0KDQojIyMgRXZhbHVhdGlvbg0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9ldmFsdWF0ZSA8LSBkZl93b3JrX3RpZHlfZXZhbHVhdGUgJT4lIA0KICBwYXJ0aXRpb24oY2x1c3RlcikgJT4lIA0KICBtdXRhdGUoDQogICAgTm9ybWFsX211bHRpX3IgPSBwdXJycjo6bWFwX2NocihEYXRhLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IE1WTjo6bXZuKC54KSRtdWx0aXZhcmlhdGVOb3JtYWxpdHkkUmVzdWx0WzNdKSwNCiAgICBOb3JtYWxfbXVsdGlfciA9IGlmZWxzZShOb3JtYWxfbXVsdGlfciA9PSAiWUVTIiwgIlNpIiwgIk5vIikNCiAgKSAlPiUgDQogIGNvbGxlY3QoKQ0KYGBgDQoNCiMjIyBDYXRlZ29yaXplIGJ5IGt1cnRvc2lzIGFuZCBza2V3bmVzcw0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9ldmFsdWF0ZSA8LSBkZl93b3JrX3RpZHlfZXZhbHVhdGUgJT4lIA0KICBtdXRhdGUoDQogICAgbm9ybV91bmkgPSBpZmVsc2Uoa3VydG9zaXNfdjEgPj0gLSAxLjUgJiBrdXJ0b3Npc192MSA8PSAxLjUgJg0KICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3NfdjEgPj0gLSAxLjUgJiBza2V3bmVzc192MSA8PSAxLjUgJg0KICAgICAgICAgICAgICAgICAgICAgICAga3VydG9zaXNfdjIgPj0gLSAxLjUgJiBrdXJ0b3Npc192MiA8PSAxLjUgJg0KICAgICAgICAgICAgICAgICAgICAgICAgc2tld25lc3NfdjIgPj0gLSAxLjUgJiBza2V3bmVzc192MiA8PSAxLjUsIA0KICAgICAgICAgICAgICAgICAgICAgICJTaSIsICJObyIpDQogICkNCmBgYA0KDQojIyBGb3JtYXQgdGlkeSBkYXRhDQoNCmBgYHtyfQ0KZGZfd29ya190aWR5X2V2YWx1YXRlIDwtIGRmX3dvcmtfdGlkeV9ldmFsdWF0ZSAlPiUNCiAgbXV0YXRlKA0KICAgIFRpcG9fU2ltID0gZmN0X3JlY29kZShUaXBvX1NpbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiIgPSAiZGF0YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPTCBNMyIgPSAiZGF0YV9vdXRfbTMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTYiID0gImRhdGFfb3V0X202IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYxIiA9ICJkYXRhX291dF9tM3YxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYyIiA9ICJkYXRhX291dF9tM3YyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE0zIFYzIiA9ICJkYXRhX291dF9tM3YzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYxIiA9ICJkYXRhX291dF9tNnYxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYyIiA9ICJkYXRhX291dF9tNnYyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYzIiA9ICJkYXRhX291dF9tNnYzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBBIiA9ICJkYXRhX25vbm9ybTEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEIiID0gImRhdGFfbm9ub3JtMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJOby1NVk4gQyIgPSAiZGF0YV9ub25vcm0zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBEIiA9ICJkYXRhX25vbm9ybTQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIEUiID0gImRhdGFfbm9ub3JtNSIpLA0KICAgIFRpcG9fU2ltID0gZmN0X3JlbGV2ZWwoVGlwb19TaW0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIiwgIk9MIE0zIiwgIk9MIE02IiwgIk9MIE0zIFYxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiT0wgTTMgVjIiLCAiT0wgTTMgVjMiLCAiT0wgTTYgVjEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9MIE02IFYyIiwgIk9MIE02IFYzIikNCiAgKSAlPiUgDQogIGFycmFuZ2UoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltKQ0KDQpkZl93b3JrX3RpZHlfZXZhbHVhdGUNCmBgYA0KDQojIyBEYXRhIGZvcm1hdCBmb3IgZXZhbHVhdGlvbg0KDQpDb21wbGV0ZToNCg0KYGBge3J9DQpkZl93b3JrX3RpZHlfQSA8LSBkZl93b3JrX3RpZHlfZXZhbHVhdGUgJT4lIA0KICBzZWxlY3QoY29ycmVsYWNpb246VGlwb19TaW0sIE5vcm1hbF9tdWx0aV9yOm5vcm1fdW5pKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBOb3JtYWxfbXVsdGlfcjpub3JtX3VuaSwNCiAgICBuYW1lc190byA9ICJFdmFsdWFjacOzbiBOb3JtYWxpZGFkIiwNCiAgICB2YWx1ZXNfdG8gPSAiRHgiDQogICkgJT4lDQogIG11dGF0ZSgNCiAgICBgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPSBpZmVsc2UoYEV2YWx1YWNpw7NuIE5vcm1hbGlkYWRgID09ICJOb3JtYWxfbXVsdGlfciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcm1hbGlkYWQgbWFyZGlhIiwgIk5vcm1hbGlkYWQgQXMgeSBLcyIpDQogICkNCmBgYA0KDQpHcm91cGVkOg0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9zaW1wX0IgPC0gZGZfd29ya190aWR5X2V2YWx1YXRlICU+JQ0KICBtdXRhdGUoDQogICAgVGlwb19TaW0gPSBmY3RfY29sbGFwc2UoVGlwb19TaW0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiIgPSAiTVZOIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTVZOIE9MIE0zIiA9ICJPTCBNMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNNiIgPSAiT0wgTTYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNVk4gT0wgTTNWIiA9IGMoIk9MIE0zIFYxIiwgIk9MIE0zIFYyIiwgIk9MIE0zIFYzIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1WTiBPTCBNNlYiID0gYygiT0wgTTYgVjEiLCAiT0wgTTYgVjIiLCAiT0wgTTYgVjMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8tTVZOIiA9IGMoIk5vLU1WTiBBIiwgIk5vLU1WTiBDIiwgIk5vLU1WTiBEIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vLU1WTiBrcysiID0gYygiTm8tTVZOIEIiLCAiTm8tTVZOIEUiKQ0KICAgICkNCiAgKSAlPiUNCiAgc2VsZWN0KGNvcnJlbGFjaW9uOlRpcG9fU2ltLCBOb3JtYWxfbXVsdGlfcjpub3JtX3VuaSkgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gTm9ybWFsX211bHRpX3I6bm9ybV91bmksDQogICAgbmFtZXNfdG8gPSAiRXZhbHVhY2nDs24gTm9ybWFsaWRhZCIsDQogICAgdmFsdWVzX3RvID0gIkR4Ig0KICApICU+JQ0KICBtdXRhdGUoDQogICAgYEV2YWx1YWNpw7NuIE5vcm1hbGlkYWRgID0gaWZlbHNlKGBFdmFsdWFjacOzbiBOb3JtYWxpZGFkYCA9PSAiTm9ybWFsX211bHRpX3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3JtYWxpZGFkIG1hcmRpYSIsICJOb3JtYWxpZGFkIEFzIHkgS3MiKQ0KICApDQpgYGANCg0KDQojIyBQbG90cw0KDQojIyMgUGxvdCBNYXJkaWEgZnVsbA0KDQpDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgZGF0YWZyYW1lcyBpZGVudGlmaWVkIGFzIG11bHRpdmFyaWF0ZSBub3JtYWwgaW4gZWFjaCBjb25kaXRpb24uDQoNCmBgYHtyfQ0KZGZfd29ya190aWR5X0FfbWFyZGlhIDwtIGRmX3dvcmtfdGlkeV9BICU+JSANCiAgZmlsdGVyKGBFdmFsdWFjacOzbiBOb3JtYWxpZGFkYCA9PSAiTm9ybWFsaWRhZCBtYXJkaWEiKSAlPiUgDQogIGNvdW50KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSwNCiAgICAgICAgRHgsIG5hbWUgPSAiQ2FudGlkYWQiKSAlPiUgDQogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIA0KICBtdXRhdGUoUG9yY2VudGFqZSA9IENhbnRpZGFkL3N1bShDYW50aWRhZCkpICU+JSANCiAgc2VsZWN0KC1DYW50aWRhZCkgJT4lIA0KICBwaXZvdF93aWRlcigNCiAgICBuYW1lc19mcm9tID0gRHgsDQogICAgdmFsdWVzX2Zyb20gPSBQb3JjZW50YWplLA0KICAgIHZhbHVlc19maWxsID0gMA0KICApICU+JSANCiAgdW5ncm91cCgpDQoNCmRmX3dvcmtfdGlkeV9BX21hcmRpYQ0KYGBgDQoNClBsb3QgZ2VuZXJhdGlvbjoNCg0KYGBge3J9DQpwbG90X0FfbWFyZGlhIDwtIGRmX3dvcmtfdGlkeV9BX21hcmRpYSAlPiUgDQogIG11dGF0ZShjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjMxIiwgIjAuNTAiKSksDQogICAgICAgICBjb3JyZWxhY2lvbiA9IGZjdF9yZXYoY29ycmVsYWNpb24pKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFNpLCB5ID0gY29ycmVsYWNpb24sDQogICAgICAgICAgICAgYWxwaGEgPSBjb3JyZWxhY2lvbiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQoU2ksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY3VyYWN5ID0gMSkpKSArDQogIGdlb21fY29sKCkgKw0KICBmYWNldF9ncmlkKG4gfiBUaXBvX1NpbSkgICsNCiAgc2NhbGVfYWxwaGFfZGlzY3JldGUoDQogICAgbmFtZSA9ICJDb3JyZWxhY2nDs24iLA0KICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKQ0KICApICsgDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBsaW1pdHMgPSBjKDAsIDEpLA0KICAgIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41MCwgMC43NSwgMSksDQogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLA0KICAgIGV4cGFuZCA9IGMoMCwgMC4xKSwNCiAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpDQogICkgKw0KICBnZW9tX2xhYmVsKA0KICAgIHNpemUgPSAzLjUsDQogICAgbGFiZWwuc2l6ZSA9IDAuMjUsIA0KICAgIGxhYmVsLnIgPSB1bml0KDAuMTUsICJsaW5lcyIpLA0KICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMTUsICJsaW5lcyIpLA0KICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLA0KICAgIHNob3cubGVnZW5kID0gRkFMU0UNCiAgKSArDQogIGxhYnMoDQogICAgeSA9ICIiLA0KICAgIHggPSAiIg0KICApICsgDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgZmFjZT0iYm9sZCIpLCANCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTEsDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgZmFjZSA9ICJib2xkIg0KICAgICksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgIHNpemU9MTEpLA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgIHNpemU9MTEpLA0KICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNiwgImxpbmVzIikNCiAgKSANCmBgYA0KDQohW10oaW1nL1Bsb3RfbWFyZGlhX2NvbXBsZXRlX3NhbXBsZS5wbmcpDQoNCg0KIyMjIFBsb3QgU2tld25lc3MgYW5kIEt1cnRvc2lzIGZ1bGwNCg0KQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIGRhdGFmcmFtZXMgaWRlbnRpZmllZCBhcyB1bml2YXJpYXRlIG5vcm1hbGl0eSBpbiBlYWNoIGNvbmRpdGlvbi4NCg0KYGBge3J9DQpkZl93b3JrX3RpZHlfQV9hc19rcyA8LSBkZl93b3JrX3RpZHlfQSAlPiUgDQogIGZpbHRlcihgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPT0gIk5vcm1hbGlkYWQgQXMgeSBLcyIpICU+JSANCiAgY291bnQoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltLA0KICAgICAgICBEeCwgbmFtZSA9ICJDYW50aWRhZCIpICU+JSANCiAgZ3JvdXBfYnkoY29ycmVsYWNpb24sIG4sIFRpcG9fU2ltKSAlPiUgDQogIG11dGF0ZShQb3JjZW50YWplID0gQ2FudGlkYWQvc3VtKENhbnRpZGFkKSkgJT4lIA0KICBzZWxlY3QoLUNhbnRpZGFkKSAlPiUgDQogIHBpdm90X3dpZGVyKA0KICAgIG5hbWVzX2Zyb20gPSBEeCwNCiAgICB2YWx1ZXNfZnJvbSA9IFBvcmNlbnRhamUsDQogICAgdmFsdWVzX2ZpbGwgPSAwDQogICkgJT4lIA0KICB1bmdyb3VwKCkNCmBgYA0KDQpQbG90IGdlbmVyYXRpb246DQoNCmBgYHtyfQ0KcGxvdF9BX2FzX2tzIDwtIGRmX3dvcmtfdGlkeV9BX2FzX2tzICU+JSANCiAgbXV0YXRlKGNvcnJlbGFjaW9uID0gZmFjdG9yKGNvcnJlbGFjaW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMC4xMiIsICIwLjIwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjAuMzEiLCAiMC41MCIpKSwNCiAgICAgICAgIGNvcnJlbGFjaW9uID0gZmN0X3Jldihjb3JyZWxhY2lvbikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gU2ksIHkgPSBjb3JyZWxhY2lvbiwNCiAgICAgICAgICAgICBhbHBoYSA9IGNvcnJlbGFjaW9uLCBsYWJlbCA9IHNjYWxlczo6cGVyY2VudChTaSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjdXJhY3kgPSAxKSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X2dyaWQobiB+IFRpcG9fU2ltKSAgKw0KICBzY2FsZV9hbHBoYV9kaXNjcmV0ZSgNCiAgICBuYW1lID0gIkNvcnJlbGFjacOzbiIsDQogICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpDQogICkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGxpbWl0cyA9IGMoMCwgMSksDQogICAgYnJlYWtzID0gYygwLCAwLjI1LCAwLjUwLCAwLjc1LCAxKSwNCiAgICBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksDQogICAgZXhwYW5kID0gYygwLCAwLjEpLA0KICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMikNCiAgKSArDQogIGdlb21fbGFiZWwoDQogICAgc2l6ZSA9IDMuNSwNCiAgICBsYWJlbC5zaXplID0gMC4yNSwgDQogICAgbGFiZWwuciA9IHVuaXQoMC4xNSwgImxpbmVzIiksDQogICAgbGFiZWwucGFkZGluZyA9IHVuaXQoMC4xNSwgImxpbmVzIiksDQogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksDQogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQ0KICApICsNCiAgbGFicygNCiAgICB5ID0gIiIsDQogICAgeCA9ICIiDQogICkgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgIHRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTEsDQogICAgICBmYWNlPSJib2xkIiksIA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMSwNCiAgICAgIGZhY2U9InBsYWluIiwNCiAgICAgIGNvbG91cj0iYmxhY2siKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTEsDQogICAgICBmYWNlID0gImJvbGQiDQogICAgKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIGZhY2U9InBsYWluIiwNCiAgICAgIGNvbG91cj0iYmxhY2siLA0KICAgICAgc2l6ZT0xMSksDQogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIGZhY2U9InBsYWluIiwNCiAgICAgIGNvbG91cj0iYmxhY2siLA0KICAgICAgc2l6ZT0xMSksDQogICAgcGFuZWwuc3BhY2luZyA9IHVuaXQoMC42LCAibGluZXMiKQ0KICApIA0KYGBgDQoNCg0KIVtdKGltZy9QbG90X2tzX2FzX2NvbXBsZXRlX3NhbXBsZS5wbmcpDQoNCiMjIyBQbG90IE1hcmRpYSBncm91cGVkDQoNCkNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZSBvZiBkYXRhZnJhbWVzIGlkZW50aWZpZWQgYXMgbXVsdGl2YXJpYXRlIG5vcm1hbCBpbiBlYWNoIGNvbmRpdGlvbi4NCg0KYGBge3J9DQpkZl93b3JrX3RpZHlfQl9tYXJkaWEgPC0gZGZfd29ya190aWR5X3NpbXBfQiAlPiUgDQogIGZpbHRlcihgRXZhbHVhY2nDs24gTm9ybWFsaWRhZGAgPT0gIk5vcm1hbGlkYWQgbWFyZGlhIikgJT4lIA0KICBjb3VudChjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0sDQogICAgICAgIER4LCBuYW1lID0gIkNhbnRpZGFkIikgJT4lIA0KICBncm91cF9ieShjb3JyZWxhY2lvbiwgbiwgVGlwb19TaW0pICU+JSANCiAgbXV0YXRlKFBvcmNlbnRhamUgPSBDYW50aWRhZC9zdW0oQ2FudGlkYWQpKSAlPiUgDQogIHNlbGVjdCgtQ2FudGlkYWQpICU+JSANCiAgcGl2b3Rfd2lkZXIoDQogICAgbmFtZXNfZnJvbSA9IER4LA0KICAgIHZhbHVlc19mcm9tID0gUG9yY2VudGFqZSwNCiAgICB2YWx1ZXNfZmlsbCA9IDANCiAgKSAlPiUgDQogIHVuZ3JvdXAoKQ0KYGBgDQoNClBsb3QgZ2VuZXJhdGlvbjoNCg0KYGBge3J9DQpwbG90X0JfbWFyZGlhIDwtIGRmX3dvcmtfdGlkeV9CX21hcmRpYSAlPiUgDQogIG11dGF0ZShjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjMxIiwgIjAuNTAiKSksDQogICAgICAgICBjb3JyZWxhY2lvbiA9IGZjdF9yZXYoY29ycmVsYWNpb24pKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFNpLCB5ID0gY29ycmVsYWNpb24sDQogICAgICAgICAgICAgYWxwaGEgPSBjb3JyZWxhY2lvbiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQoU2ksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY3VyYWN5ID0gMSkpKSArDQogIGdlb21fY29sKCkgKw0KICBmYWNldF9ncmlkKG4gfiBUaXBvX1NpbSkgICsNCiAgc2NhbGVfYWxwaGFfZGlzY3JldGUoDQogICAgbmFtZSA9ICJDb3JyZWxhY2nDs24iLA0KICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKQ0KICApICsgDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBsaW1pdHMgPSBjKDAsIDEpLA0KICAgIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41MCwgMC43NSwgMSksDQogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLA0KICAgIGV4cGFuZCA9IGMoMCwgMC4xKSwNCiAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpDQogICkgKw0KICBnZW9tX2xhYmVsKA0KICAgIHNpemUgPSAzLjUsDQogICAgbGFiZWwuc2l6ZSA9IDAuMjUsIA0KICAgIGxhYmVsLnIgPSB1bml0KDAuMTUsICJsaW5lcyIpLA0KICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMTUsICJsaW5lcyIpLA0KICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLA0KICAgIHNob3cubGVnZW5kID0gRkFMU0UNCiAgKSArDQogIGxhYnMoDQogICAgeSA9ICIiLA0KICAgIHggPSAiIg0KICApICsgDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgZmFjZT0iYm9sZCIpLCANCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTEsDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgZmFjZSA9ICJib2xkIg0KICAgICksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgIHNpemU9MTEpLA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgIHNpemU9MTEpLA0KICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNiwgImxpbmVzIikNCiAgKSANCmBgYA0KDQohW10oaW1nL1Bsb3RfbWFyZGlhX2dyb3VwZWRfY29tcGxldGVfc2l6ZS5wbmcpDQoNCg0KIyMjIFBsb3QgU2tld25lc3MgYW5kIEt1cnRvc2lzIGdyb3VwZWQNCg0KDQpDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgZGF0YWZyYW1lcyBpZGVudGlmaWVkIGFzIHVuaXZhcmlhdGUgbm9ybWFsaXR5IGluIGVhY2ggY29uZGl0aW9uLg0KDQpgYGB7cn0NCmRmX3dvcmtfdGlkeV9CX2FzX2tzIDwtIGRmX3dvcmtfdGlkeV9zaW1wX0IgJT4lIA0KICBmaWx0ZXIoYEV2YWx1YWNpw7NuIE5vcm1hbGlkYWRgID09ICJOb3JtYWxpZGFkIEFzIHkgS3MiKSAlPiUgDQogIGNvdW50KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSwNCiAgICAgICAgRHgsIG5hbWUgPSAiQ2FudGlkYWQiKSAlPiUgDQogIGdyb3VwX2J5KGNvcnJlbGFjaW9uLCBuLCBUaXBvX1NpbSkgJT4lIA0KICBtdXRhdGUoUG9yY2VudGFqZSA9IENhbnRpZGFkL3N1bShDYW50aWRhZCkpICU+JSANCiAgc2VsZWN0KC1DYW50aWRhZCkgJT4lIA0KICBwaXZvdF93aWRlcigNCiAgICBuYW1lc19mcm9tID0gRHgsDQogICAgdmFsdWVzX2Zyb20gPSBQb3JjZW50YWplLA0KICAgIHZhbHVlc19maWxsID0gMA0KICApICU+JSANCiAgdW5ncm91cCgpDQpgYGANCg0KUGxvdCBHZW5lcmF0aW9uOg0KDQpgYGB7cn0NCnBsb3RfQl9hc19rcyA8LSBkZl93b3JrX3RpZHlfQl9hc19rcyAlPiUgDQogIG11dGF0ZShjb3JyZWxhY2lvbiA9IGZhY3Rvcihjb3JyZWxhY2lvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAuMTIiLCAiMC4yMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjMxIiwgIjAuNTAiKSksDQogICAgICAgICBjb3JyZWxhY2lvbiA9IGZjdF9yZXYoY29ycmVsYWNpb24pKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IFNpLCB5ID0gY29ycmVsYWNpb24sDQogICAgICAgICAgICAgYWxwaGEgPSBjb3JyZWxhY2lvbiwgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQoU2ksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjY3VyYWN5ID0gMSkpKSArDQogIGdlb21fY29sKCkgKw0KICBmYWNldF9ncmlkKG4gfiBUaXBvX1NpbSkgICsNCiAgc2NhbGVfYWxwaGFfZGlzY3JldGUoDQogICAgbmFtZSA9ICJDb3JyZWxhY2nDs24iLA0KICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKQ0KICApICsgDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBsaW1pdHMgPSBjKDAsIDEpLA0KICAgIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41MCwgMC43NSwgMSksDQogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLA0KICAgIGV4cGFuZCA9IGMoMCwgMC4xKSwNCiAgICBndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDIpDQogICkgKw0KICBnZW9tX2xhYmVsKA0KICAgIHNpemUgPSAzLjUsDQogICAgbGFiZWwuc2l6ZSA9IDAuMjUsIA0KICAgIGxhYmVsLnIgPSB1bml0KDAuMTUsICJsaW5lcyIpLA0KICAgIGxhYmVsLnBhZGRpbmcgPSB1bml0KDAuMTUsICJsaW5lcyIpLA0KICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLA0KICAgIHNob3cubGVnZW5kID0gRkFMU0UNCiAgKSArDQogIGxhYnMoDQogICAgeSA9ICIiLA0KICAgIHggPSAiIg0KICApICsgDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwNCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgZmFjZT0iYm9sZCIpLCANCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBzaXplID0gMTEsDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KA0KICAgICAgc2l6ZSA9IDExLA0KICAgICAgZmFjZSA9ICJib2xkIg0KICAgICksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgIHNpemU9MTEpLA0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICBmYWNlPSJwbGFpbiIsDQogICAgICBjb2xvdXI9ImJsYWNrIiwNCiAgICAgIHNpemU9MTEpLA0KICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNiwgImxpbmVzIikNCiAgKSANCmBgYA0KDQohW10oaW1nL1Bsb3Rfa3NfYXNfZ3JvdXBlZF9jb21wbGV0ZV9zaXplLnBuZyk=